import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_loggy_dio/flutter_loggy_dio.dart';
import 'package:loggy/loggy.dart';
// import 'package:moling/common/Global.dart';
// import 'package:moling/utils/ToastUtils.dart';

import '../common/BaseEntity.dart';
import 'error_handle.dart';
import 'http_config.dart';

class HttpRequest {
  static HttpRequest instance = HttpRequest._internal();

  static Map<String, dynamic> headers = {};

  static Dio _dio = Dio();

  static Dio _dioStream = Dio();

  HttpRequest._internal() {
    BaseOptions options = BaseOptions(
      baseUrl: HTTPConfig.baseURL,
      connectTimeout: const Duration(milliseconds: HTTPConfig.timeout),
      receiveTimeout: const Duration(milliseconds: HTTPConfig.timeout),
    );
    instance = this;
    _dio = Dio(options);
    BaseOptions optionsStream = BaseOptions(
      baseUrl: HTTPConfig.baseURL,
      responseType: ResponseType.stream,
      connectTimeout: const Duration(milliseconds: HTTPConfig.timeout),
      receiveTimeout: const Duration(milliseconds: HTTPConfig.timeout),
    );
    _dioStream = Dio(optionsStream);
    _dio.interceptors.add(
      InterceptorsWrapper(onRequest: _onRequest, onResponse: _onResponse),
    );
    _dioStream.interceptors.add(
      InterceptorsWrapper(onRequest: _onRequestStream, onResponse: _onResponse),
    );
    // _dio.interceptors.add(WaterMarkInterceptor());
    _dio.interceptors.add(
      LoggyDioInterceptor(
        requestLevel: LogLevel.all,
        requestHeader: true,
        requestBody: true,
        responseHeader: true,
      ),
    );
    _dioStream.interceptors.add(
      LoggyDioInterceptor(
        requestLevel: LogLevel.all,
        requestHeader: true,
        requestBody: true,
        responseHeader: true,
      ),
    );
  }

  void _onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    options.headers = headers;
    options.responseType = ResponseType.plain;
    options.contentType = "application/json";
    handler.next(options);
  }

  void _onRequestStream(
    RequestOptions options,
    RequestInterceptorHandler handler,
  ) {
    options.headers = headers;
    options.responseType = ResponseType.stream;
    handler.next(options);
  }

  void _onResponse(
    Response response,
    ResponseInterceptorHandler handler,
  ) async {
    handler.next(response);
  }

  Future<Stream<List<int>>> requestStream(
    String url, {
    Object? data,
    Map<String, dynamic>? queryParameters,
    CancelToken? cancelToken,
  }) async {
    try {
      final response = await _dioStream.post(
        url,
        data: data,
        queryParameters: queryParameters,
        options: Options(
          responseType: ResponseType.stream,
          headers: {
            'Content-Type': 'application/json',
            'Authorization': headers['Authorization'],
          },
        ),
        cancelToken: cancelToken,
      );

      // 检查响应类型
      if (response.data is ResponseBody) {
        final responseBody = response.data as ResponseBody;
        // 如果是错误响应，读取错误信息
        if (response.statusCode != 200) {
          String errorBody = await utf8.decodeStream(responseBody.stream);
          try {
            // 尝试解析错误JSON
            Map<String, dynamic> errorJson = json.decode(errorBody);
            throw DioException(
              requestOptions: response.requestOptions,
              response: response,
              message: errorJson['message'] ?? errorJson['error'] ?? '请求失败',
            );
          } catch (e) {
            // JSON解析失败，直接返回原始错误信息
            throw DioException(
              requestOptions: response.requestOptions,
              response: response,
              message: errorBody,
            );
          }
        }
        return responseBody.stream;
      } else {
        throw DioException(
          requestOptions: response.requestOptions,
          message: '响应格式错误',
        );
      }
    } on DioException catch (e) {
      if (e.type == DioExceptionType.cancel) {
        rethrow; // 重新抛出取消异常
      }

      // 处理其他Dio异常
      String errorMessage = '请求失败';
      if (e.response?.data != null) {
        if (e.response!.data is Map) {
          errorMessage =
              e.response!.data['message'] ??
              e.response!.data['error'] ??
              '请求失败';
        } else if (e.response!.data is String) {
          try {
            Map<String, dynamic> errorJson = json.decode(e.response!.data);
            errorMessage = errorJson['message'] ?? errorJson['error'] ?? '请求失败';
          } catch (_) {
            errorMessage = e.response!.data;
          }
        }
      }
      throw DioException(
        requestOptions: e.requestOptions,
        response: e.response,
        message: errorMessage,
      );
    } catch (e) {
      throw DioException(
        requestOptions: RequestOptions(path: url),
        message: e.toString(),
      );
    }
  }

  Future<String> requestCommon(
    String method,
    String url, {
    Object? data,
    Map<String, dynamic>? queryParameters,
    CancelToken? cancelToken,
    Options? options,
  }) async {
    options = Options(method: method);
    final Response<String> response = await _dio.request<String>(
      url,
      data: data,
      queryParameters: queryParameters,
      options: _checkOptions(method, options),
      cancelToken: cancelToken,
    );
    final String result = response.data.toString();
    return result;
  }

  // 数据返回格式统一，统一处理异常
  Future<BaseEntity<T>> _request<T>(
    String method,
    String url, {
    Object? data,
    Map<String, dynamic>? queryParameters,
    CancelToken? cancelToken,
    Options? options,
  }) async {
    options = Options(method: method);
    final Response<String> response = await _dio.request<String>(
      url,
      data: data,
      queryParameters: queryParameters,
      options: _checkOptions(method, options),
      cancelToken: cancelToken,
    );
    final String responseData = response.data.toString();

    try {
      final Map<String, dynamic> map = parseData(responseData);
      // print("url: $url, responseData: $responseData");
      if (map.containsKey('status')) {
        if (map['status'] == 1) {
          BaseEntity<T> entity = BaseEntity<T>.fromJson(map);
          return entity;
        } else {
          return BaseEntity<T>(map['status'], map['code'], map['data']);
        }
      } else {
        return BaseEntity<T>(0, ExceptionHandle.parse_error, null);
      }
    } catch (e) {
      print('url = $url, error: $e');
      return BaseEntity<T>(0, ExceptionHandle.parse_error, null);
    }
  }

  Future<dynamic> requestNetwork<T>(
    String url, {
    String method = 'get',
    NetSuccessCallback<T?>? onSuccess,
    NetErrorCallback? onError,
    Object? params,
    Map<String, dynamic>? queryParameters,
    CancelToken? cancelToken,
    Options? options,
  }) {
    return _request<T>(
      method,
      url,
      data: params,
      queryParameters: queryParameters,
      options: options,
      cancelToken: cancelToken,
    ).then<void>(
      (BaseEntity<T> result) {
        print('status == ${result.status}: code = ${result.code}: url = $url');
        if (result.status == 1) {
          try {
            onSuccess?.call(result.data);
          } catch (e) {
            _onError(result.code, e.toString(), onError);
          }
        } else {
          // print('status == ${result.status}: url = $url, result: $result');
          _onError(result.code, '${result.data}', onError);
        }
      },
      onError: (dynamic e) {
        print('url = $url, error: $e');
        final NetError error = ExceptionHandle.handleException(e);
        _onError(error.code, error.msg, onError);
      },
    );
  }

  bool checkTokenError(int code) {
    return code == 10000 ||
        code == 10001 ||
        code == 10002 ||
        code == 10003 ||
        code == 10004 ||
        code == 10005 ||
        code == 10006;
  }

  Options _checkOptions(String method, Options? options) {
    options ??= Options();
    options.method = method;
    return options;
  }

  Map<String, dynamic> parseData(String data) {
    return json.decode(data) as Map<String, dynamic>;
  }

  void addHeaders(Map<String, dynamic>? newHeaders) {
    if (newHeaders != null && newHeaders.isNotEmpty) {
      headers.addAll(newHeaders);
    }
  }

  void addHeader(String key, String value, {required}) {
    headers[key] = value;
  }

  void _onError(int? code, String? msg, NetErrorCallback? onError) {
    if (code == null) {
      code = ExceptionHandle.unknown_error;
      msg = '未知异常';
    }
    if (kDebugMode) {
      print("request error---$code---$msg");
    }
    onError?.call(code, msg ?? '');
  }

  void clearToken() {
    headers.remove('Authorization');
  }
}

typedef NetSuccessCallback<T> = Function(T data);
typedef NetSuccessListCallback<T> = Function(List<T> data);
typedef NetErrorCallback = Function(int code, String msg);
